#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
经验系统模块
负责角色经验计算、升级判断和成长曲线管理
"""

import math
from typing import Dict, Tuple, List
from dataclasses import dataclass


@dataclass
class LevelInfo:
    """等级信息"""
    level: int
    total_exp_required: int  # 从1级到该等级所需的总经验
    exp_for_this_level: int  # 该等级本身需要的经验
    exp_to_next_level: int   # 到下一级还需要的经验


class ExperienceSystem:
    """经验系统类"""
    
    def __init__(self):
        # 经验成长曲线参数
        self.base_exp = 100          # 基础经验值
        self.growth_factor = 1.15    # 成长因子
        self.level_power = 1.8       # 等级指数
        self.max_level = 100         # 最大等级
        
        # 缓存计算结果
        self._level_cache: Dict[int, LevelInfo] = {}
        self._precompute_levels()
    
    def _precompute_levels(self):
        """预计算所有等级的经验需求"""
        total_exp = 0
        
        for level in range(1, self.max_level + 1):
            if level == 1:
                exp_for_level = 0
                exp_to_next = self.calculate_exp_for_level(2)
            else:
                exp_for_level = self.calculate_exp_for_level(level)
                total_exp += exp_for_level
                exp_to_next = self.calculate_exp_for_level(level + 1) if level < self.max_level else 0
            
            self._level_cache[level] = LevelInfo(
                level=level,
                total_exp_required=total_exp,
                exp_for_this_level=exp_for_level,
                exp_to_next_level=exp_to_next
            )
    
    def calculate_exp_for_level(self, level: int) -> int:
        """
        计算从level-1升到level需要的经验
        
        使用公式: base_exp * (level^level_power) * (growth_factor^(level-1))
        
        Args:
            level: 目标等级
            
        Returns:
            升级所需经验
        """
        if level <= 1:
            return 0
        
        # 指数增长公式，确保后期升级难度显著增加
        exp_needed = self.base_exp * (level ** self.level_power) * (self.growth_factor ** (level - 2))
        return int(exp_needed)
    
    def get_level_info(self, level: int) -> LevelInfo:
        """
        获取等级信息
        
        Args:
            level: 等级
            
        Returns:
            等级信息对象
        """
        if level < 1:
            level = 1
        elif level > self.max_level:
            level = self.max_level
            
        return self._level_cache.get(level, self._level_cache[1])
    
    def calculate_level_from_exp(self, total_exp: int) -> Tuple[int, int]:
        """
        根据总经验计算当前等级和剩余经验
        
        Args:
            total_exp: 总经验值
            
        Returns:
            (当前等级, 当前等级的剩余经验)
        """
        if total_exp <= 0:
            return 1, 0
        
        # 二分查找确定等级
        left, right = 1, self.max_level
        current_level = 1
        
        while left <= right:
            mid = (left + right) // 2
            level_info = self.get_level_info(mid)
            
            if total_exp >= level_info.total_exp_required:
                current_level = mid
                left = mid + 1
            else:
                right = mid - 1
        
        # 计算当前等级的剩余经验
        level_info = self.get_level_info(current_level)
        remaining_exp = total_exp - level_info.total_exp_required
        
        return current_level, remaining_exp
    
    def can_level_up(self, current_level: int, current_exp: int) -> bool:
        """
        判断是否可以升级
        
        Args:
            current_level: 当前等级
            current_exp: 当前等级的经验
            
        Returns:
            是否可以升级
        """
        if current_level >= self.max_level:
            return False
        
        level_info = self.get_level_info(current_level)
        return current_exp >= level_info.exp_to_next_level
    
    def process_level_up(self, current_level: int, current_exp: int) -> Tuple[int, int, List[int]]:
        """
        处理升级，可能连续升多级
        
        Args:
            current_level: 当前等级
            current_exp: 当前等级的经验
            
        Returns:
            (新等级, 新等级的剩余经验, 升级的等级列表)
        """
        levels_gained = []
        
        while self.can_level_up(current_level, current_exp) and current_level < self.max_level:
            level_info = self.get_level_info(current_level)
            current_exp -= level_info.exp_to_next_level
            current_level += 1
            levels_gained.append(current_level)
        
        return current_level, current_exp, levels_gained
    
    def get_exp_progress(self, current_level: int, current_exp: int) -> Dict[str, any]:
        """
        获取经验进度信息
        
        Args:
            current_level: 当前等级
            current_exp: 当前等级的经验
            
        Returns:
            经验进度信息
        """
        level_info = self.get_level_info(current_level)
        
        if current_level >= self.max_level:
            progress_percentage = 100.0
            exp_to_next = 0
        else:
            progress_percentage = (current_exp / level_info.exp_to_next_level) * 100 if level_info.exp_to_next_level > 0 else 100.0
            exp_to_next = max(0, level_info.exp_to_next_level - current_exp)
        
        return {
            'current_level': current_level,
            'current_exp': current_exp,
            'exp_to_next_level': level_info.exp_to_next_level,
            'exp_needed_for_next': exp_to_next,
            'progress_percentage': min(100.0, progress_percentage),
            'total_exp_for_level': level_info.total_exp_required,
            'is_max_level': current_level >= self.max_level
        }
    
    def calculate_idle_exp_rate(self, character_level: int, location_multiplier: float = 1.0) -> float:
        """
        计算挂机经验获取速率
        
        Args:
            character_level: 角色等级
            location_multiplier: 地点经验倍率
            
        Returns:
            每小时经验获取量
        """
        # 基础经验速率随等级增长，但增长率递减
        base_rate = 50 + (character_level * 10)  # 基础每小时50经验，每级增加10
        
        # 等级加成，但有上限避免高等级过于强势
        level_bonus = min(character_level * 0.05, 2.0)  # 每级5%加成，最高200%
        
        # 高等级效率递减，避免高等级角色在低等级地图刷经验
        efficiency = 1.0
        if character_level > 20:
            efficiency = max(0.5, 1.0 - (character_level - 20) * 0.01)  # 20级后每级减少1%效率，最低50%
        
        final_rate = base_rate * (1 + level_bonus) * location_multiplier * efficiency
        return max(1.0, final_rate)  # 最低每小时1经验
    
    def get_level_ranges_for_locations(self) -> List[Dict[str, any]]:
        """
        获取推荐的挂机地点等级范围
        
        Returns:
            地点等级范围列表
        """
        return [
            {
                'name': '新手村',
                'min_level': 1,
                'max_level': 8,
                'optimal_range': (1, 5),
                'base_multiplier': 1.0,
                'description': '适合新手练级的安全区域'
            },
            {
                'name': '森林边缘',
                'min_level': 5,
                'max_level': 15,
                'optimal_range': (6, 12),
                'base_multiplier': 1.3,
                'description': '怪物较弱的森林外围'
            },
            {
                'name': '深林密境',
                'min_level': 12,
                'max_level': 25,
                'optimal_range': (15, 22),
                'base_multiplier': 1.6,
                'description': '危险但收益丰厚的深林区域'
            },
            {
                'name': '山洞入口',
                'min_level': 20,
                'max_level': 35,
                'optimal_range': (23, 32),
                'base_multiplier': 1.8,
                'description': '洞穴怪物聚集地'
            },
            {
                'name': '古老遗迹',
                'min_level': 30,
                'max_level': 50,
                'optimal_range': (35, 45),
                'base_multiplier': 2.2,
                'description': '充满神秘力量的遗迹'
            },
            {
                'name': '龙穴深处',
                'min_level': 45,
                'max_level': 100,
                'optimal_range': (50, 80),
                'base_multiplier': 3.0,
                'description': '传说中的龙族栖息地'
            }
        ]
    
    def print_level_table(self, max_level: int = 20):
        """
        打印等级表，用于调试和查看
        
        Args:
            max_level: 显示的最大等级
        """
        print(f"{'等级':<4} {'本级经验':<10} {'累计经验':<12} {'到下级':<10}")
        print("-" * 40)
        
        for level in range(1, min(max_level + 1, self.max_level + 1)):
            info = self.get_level_info(level)
            print(f"{level:<4} {info.exp_for_this_level:<10} {info.total_exp_required:<12} {info.exp_to_next_level:<10}")


# 全局经验系统实例
exp_system = ExperienceSystem()


if __name__ == "__main__":
    # 测试经验系统
    exp_sys = ExperienceSystem()
    
    print("=== 经验成长曲线测试 ===")
    exp_sys.print_level_table(30)
    
    print("\n=== 挂机经验速率测试 ===")
    for level in [1, 5, 10, 20, 30, 50]:
        rate = exp_sys.calculate_idle_exp_rate(level, 1.5)
        print(f"等级 {level}: 每小时 {rate:.1f} 经验")
    
    print("\n=== 升级测试 ===")
    current_level, current_exp = 5, 200
    new_level, new_exp, levels = exp_sys.process_level_up(current_level, current_exp)
    print(f"从 {current_level} 级 {current_exp} 经验 -> {new_level} 级 {new_exp} 经验")
    print(f"升级路径: {levels}")